
package org.mymybatis.session;


import org.mymybatis.mapping.MappedStatement;
import org.mymybatis.transaction.Transaction;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;

/**
 * 执行sql语句的对象
 */
public class SqlSession {

    private Transaction transaction;
    private Map<String, MappedStatement> mappedStatements;


    public static void main(String[] args) {
        String sql = "insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})";
        Map<Integer, String> map = new HashMap<>();
        int index = 1;
        while (sql.indexOf("#") >= 0) {
            int beginIndex = sql.indexOf("#") + 2;
            int endIndex = sql.indexOf("}");
            map.put(index++, sql.substring(beginIndex, endIndex).trim());
            sql = sql.substring(endIndex + 1);
        }
        System.out.println(map.toString());
    }

    public int insert(String sqlId, Object obj) throws SQLException {
        Connection connection = transaction.getConnection();
        MappedStatement mappedStatement = mappedStatements.get(sqlId);
        // insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
        String oldSql = mappedStatement.getSql();
        String newSql = oldSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?");
        // insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)

        Map<Integer, String> map = new HashMap<>();
        int index = 1;
        while (oldSql.indexOf("#") >= 0) {
            int beginIndex = oldSql.indexOf("#") + 2;
            int endIndex = oldSql.indexOf("}");
            map.put(index++, oldSql.substring(beginIndex, endIndex).trim());
            oldSql = oldSql.substring(endIndex + 1);
        }
        final PreparedStatement ps;

        try {
            ps = connection.prepareStatement(newSql);
            // 给?赋值
            map.forEach((k, v) -> {
                try {
                    // 获取java实体类的get方法名
                    String getMethodName = "get" + v.toUpperCase().charAt(0) + v.substring(1);
                    Method getMethod = obj.getClass().getDeclaredMethod(getMethodName);
                    ps.setString(k, getMethod.invoke(obj).toString());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            int count = ps.executeUpdate();
            ps.close();
            return count;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }



    public Object selectOne(String sqlId, Object parameterObj) throws SQLException {
        MappedStatement mappedStatement = mappedStatements.get(sqlId);
        Connection connection = transaction.getConnection();
        // 获取sql语句
        String oldSql = mappedStatement.getSql();
        String newSql = oldSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?");
        // 执行sql
        PreparedStatement ps = null;
        ResultSet rs = null;
        Object obj = null;
        try {
            ps = connection.prepareStatement(newSql);
            ps.setString(1, parameterObj.toString());
            rs = ps.executeQuery();
            if (rs.next()) {
                // 将结果集封装对象，通过反射
                String resultType = mappedStatement.getResultType();
                Class<?> aClass = Class.forName(resultType);
                Constructor<?> con = aClass.getDeclaredConstructor();
                obj = con.newInstance();
                // 给对象obj属性赋值
                ResultSetMetaData rsmd = rs.getMetaData();
                int columnCount = rsmd.getColumnCount();
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = rsmd.getColumnName(i);
                    String setMethodName = "set" + columnName.toUpperCase().charAt(0) + columnName.substring(1);
                    Method setMethod = aClass.getDeclaredMethod(setMethodName, aClass.getDeclaredField(columnName).getType());
                    setMethod.invoke(obj, rs.getString(columnName));
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            try {
                ps.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        return obj;
    }


    public void commit() {
        try {
            transaction.getConnection().commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void rollback() {
        try {
            transaction.getConnection().rollback();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public void close() {
        try {
            transaction.getConnection().close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }


    public SqlSession() {
    }

    public SqlSession(Transaction transaction, Map<String, MappedStatement> mappedStatements) {
        this.transaction = transaction;
        this.mappedStatements = mappedStatements;
    }

    public Transaction getTransaction() {
        return transaction;
    }

    public void setTransaction(Transaction transaction) {
        this.transaction = transaction;
    }

    public Map<String, MappedStatement> getMappedStatements() {
        return mappedStatements;
    }

    public void setMappedStatements(Map<String, MappedStatement> mappedStatements) {
        this.mappedStatements = mappedStatements;
    }
}
